package com.woniuxy.juc.writeandread;

import com.woniuxy.untis.Sleep;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.StampedLock;

/**
 * <P> @Author: ideaAdmin
 * <P> TODO: Class
 * <P> TODO: 读写锁
 * <P> Date: 2022/4/12:10:06
 * <P> Description:
 */
@Slf4j(topic = "c.c")
@SuppressWarnings("all")
public class StampedLockTest {
    public static void main(String[] args) {
        DataContainerStamped dataContainer = new DataContainerStamped(1);
        new Thread(()->{
            dataContainer.read(1000);
        },"t1").start();

        Sleep.sleep(500);

        new Thread(()->{
            dataContainer.read(0);
        },"t2").start();
    }
}

@Slf4j(topic = "c.c")
class DataContainerStamped {
    private int data;
    private final StampedLock lock = new StampedLock();

    public DataContainerStamped(int data) {
        this.data = data;
    }

    public int read(int readTime) {
        //TODO 尝试乐观阅读  不上锁
        long stamp = lock.tryOptimisticRead();
        log.debug("optimistic read lock {}", stamp);
        Sleep.sleep(readTime);

        //TODO 戳验证
        if (lock.validate(stamp)) {
            log.debug("read finish.. {}", stamp);
            return data;
        }

        log.debug("updating to read lock.. {}", stamp);

        //TODO 锁升级 读锁
        try {
            stamp = lock.readLock();
            log.debug("read lock {}", stamp);
            Sleep.sleep(readTime);
            log.debug("read finish.. {}", stamp);
            return data;
        } finally {
            log.debug("read unlock {}", stamp);
            lock.unlockRead(stamp);
        }
    }

    public void write(int newData) {
        long stamp = lock.writeLock();
        log.debug("write lock {}", stamp);

        try {
            Sleep.sleep(2L);
            this.data = newData;
        } finally {
            log.debug("write unlock {}", stamp);
            lock.unlock(stamp);
        }
    }
}
